/* eslint-disable @typescript-eslint/no-explicit-any */
import { type ElementProps, WebComponents } from '@knno/jsx';

interface ClassType<T extends HTMLElement> {
	new (...argc: any[]): T;
	prototype: T;
}

type Connectable<T> = {
	onConnected?: (this: T) => void;
	onDisconnected?: (this: T) => void;
};

// 工具类型，判断两个类型是否严格相等
type IsExactType<T, U> = (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2
	? true
	: false;

export function defineElement<C extends ClassType<HTMLElement>>(
	tagName: `${string}-${string}`,
	baseClass: IsExactType<C, typeof HTMLElement> extends true ? C : never,
): (props: ElementProps<HTMLElement> & Connectable<HTMLElement>) => HTMLElement;

export function defineElement<
	C extends ClassType<HTMLElement>,
	T extends HTMLElement = InstanceType<C>,
>(
	tagName: `${string}-${string}`,
	baseClass: C,
	extend: string,
): (props: ElementProps<T> & Connectable<T>) => T;

export function defineElement<
	C extends ClassType<HTMLElement>,
	T extends HTMLElement = InstanceType<C>,
>(
	tagName: `${string}-${string}`,
	baseClass: C,
	extend?: string,
): (props: ElementProps<T> & Connectable<T>) => T {
	class RootElement extends baseClass {
		connectedCallback() {
			this.dispatchEvent(new CustomEvent('connected'));
		}
		disconnectedCallback() {
			this.dispatchEvent(new CustomEvent('disconnected'));
		}
	}
	return WebComponents.register<ElementProps<T> & Connectable<T>, T>(
		RootElement as any,
		tagName,
		extend,
	);
}
